import { CALL_API, Schemas } from '../middleware/api';

export const USER_REQUEST = 'USER_REQUEST';
export const USER_SUCCESS = 'USER_SUCCESS';
export const USER_FAILURE = 'USER_FAILURE';

// Fetches a single user from Github API.
// 这个action创建函数之所以可以返回一个key为[CALL_API]的对象，就是得益于API中间件的定制加工(../middleware/api.js)。
// 其中，CALL_API 来自中间件的 export const CALL_API=Symbol('Call API');，
// 它是个Symbol类型。Symbol是一个唯一的、不变的标识，可以用作对象的key。
// 它是为了避免命名冲突而生的，这里也可以用字符串来代替，不过你就要自己保证命名不发生冲突了。
function fetchUser(login) {
    return {
        [CALL_API]: {
            types: [USER_REQUEST, USER_SUCCESS, USER_FAILURE],
            endpoint: `users/${login}`,
            schema: Schemas.USER,
        },
    };
}

// Fetches a single user from Github API unless it is cached.
// Relies on Redux Thunk middleware.
export function loadUser(login, requiredFields = []) {
    return (dispatch, getState) => {
        const user = getState().entities.users[login];
        if (user && requiredFields.every(key => user.hasOwnProperty(key))) {
            return null;
        }

        return dispatch(fetchUser(login));
    };
}

export const REPO_REQUEST = 'REPO_REQUEST';
export const REPO_SUCCESS = 'REPO_SUCCESS';
export const REPO_FAILURE = 'REPO_FAILURE';

// Fetches a single repository from Github API.
// Relies on the custom API middleware defined in ../middleware/api.js.
function fetchRepo(fullName) {
    return {
        [CALL_API]: {
            types: [REPO_REQUEST, REPO_SUCCESS, REPO_FAILURE],
            endpoint: `repos/${fullName}`,
            schema: Schemas.REPO,
        },
    };
}

// Fetches a single repository from Github API unless it is cached.
// Relies on Redux Thunk middleware.
export function loadRepo(fullName, requiredFields = []) {
    return (dispatch, getState) => {
        const repo = getState().entities.repos[fullName];
        if (repo && requiredFields.every(key => repo.hasOwnProperty(key))) {
            return null;
        }

        return dispatch(fetchRepo(fullName));
    };
}

export const STARRED_REQUEST = 'STARRED_REQUEST';
export const STARRED_SUCCESS = 'STARRED_SUCCESS';
export const STARRED_FAILURE = 'STARRED_FAILURE';

// Fetches a page of starred repos by a particular user.
// Relies on the custom API middleware defined in ../middleware/api.js.
function fetchStarred(login, nextPageUrl) {
    return {
        login,
        [CALL_API]: {
            types: [STARRED_REQUEST, STARRED_SUCCESS, STARRED_FAILURE],
            endpoint: nextPageUrl,
            schema: Schemas.REPO_ARRAY,
        },
    };
}

// Fetches a page of starred repos by a particular user.
// Bails out if page is cached and user didn’t specifically request next page.
// Relies on Redux Thunk middleware.
export function loadStarred(login, nextPage) {
    return (dispatch, getState) => {
        const {
            nextPageUrl = `users/${login}/starred`,
            pageCount = 0,
        } = getState().pagination.starredByUser[login] || {};

        if (pageCount > 0 && !nextPage) {
            return null;
        }

        return dispatch(fetchStarred(login, nextPageUrl));
    };
}

export const STARGAZERS_REQUEST = 'STARGAZERS_REQUEST';
export const STARGAZERS_SUCCESS = 'STARGAZERS_SUCCESS';
export const STARGAZERS_FAILURE = 'STARGAZERS_FAILURE';

// Fetches a page of stargazers for a particular repo.
// Relies on the custom API middleware defined in ../middleware/api.js.
function fetchStargazers(fullName, nextPageUrl) {
    return {
        fullName,
        [CALL_API]: {
            types: [STARGAZERS_REQUEST, STARGAZERS_SUCCESS, STARGAZERS_FAILURE],
            endpoint: nextPageUrl,
            schema: Schemas.USER_ARRAY,
        },
    };
}

// Fetches a page of stargazers for a particular repo.
// Bails out if page is cached and user didn’t specifically request next page.
// Relies on Redux Thunk middleware.
export function loadStargazers(fullName, nextPage) {
    return (dispatch, getState) => {
        const {
            nextPageUrl = `repos/${fullName}/stargazers`,
            pageCount = 0,
        } = getState().pagination.stargazersByRepo[fullName] || {};

        if (pageCount > 0 && !nextPage) {
            return null;
        }

        return dispatch(fetchStargazers(fullName, nextPageUrl));
    };
}

export const RESET_ERROR_MESSAGE = 'RESET_ERROR_MESSAGE';

// Resets the currently visible error message.
export function resetErrorMessage() {
    return {
        type: RESET_ERROR_MESSAGE,
    };
}
